package com.c5p1ng.route.ribbon;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.c5p1ng.route.context.GlobalContext;
import com.c5p1ng.route.util.ContextUtil;
import com.c5p1ng.route.util.LocalIpUtil;
import com.c5p1ng.route.util.SpringContextUtil;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;
import java.util.List;


/**
 * Nacos路由选择器
 *
 * @author csp
 **/
public class NacosLoadBalancerRule extends AbstractLoadBalancerRule {
    private static final Logger LOGGER = LoggerFactory.getLogger(NacosLoadBalancerRule.class);

    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Resource
    private NacosServiceManager nacosServiceManager;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }

    @Override
    public Server choose(Object o) {
        DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
        String name = loadBalancer.getName();
        try {
            GlobalContext globalContext = ContextUtil.getCurrentContext();
            if(globalContext == null) {
                globalContext = new GlobalContext();
            }
            String group = globalContext.getGroup();
            if(group == null) {
                ApplicationContext context = SpringContextUtil.getContext();
                if(context != null) {
                    group = context.getEnvironment().getProperty("spring.cloud.nacos.discovery.group", "DEFAULT_GROUP");
                } else {
                    group = "DEFAULT_GROUP";
                }
            }
            Instance instance = getInstance(name, group, globalContext.getClientIp());
            LOGGER.info("请求服务:{}", instance != null ? instance.getInstanceId() : null);
            return new NacosServer(instance);
        } catch (NacosException e) {
            LOGGER.error("获取nacos服务异常!异常信息:{}", e);
        } catch (Exception e) {
            LOGGER.error("请求服务异常!异常信息:{}", e);
        }
        return null;
    }

    private Instance getInstance(String serviceName, String groupName, String clientIp) throws NacosException {
        LOGGER.debug("getInstance serviceName:{}, groupName:{}, clientIp:{}", serviceName, groupName, clientIp);
        NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());
        List<Instance> instances = namingService.selectInstances(serviceName, groupName, true);
        if (instances == null || instances.size() == 0) {
            LOGGER.warn("Nacos服务列表为空!");
            return null;
        }
        //优先本机匹配
        for(Instance instance : instances) {
            if (clientIp == null) {
                clientIp = LocalIpUtil.getLocalIp();
            }
            if (clientIp.equals(instance.getIp())) {
                return instance;
            }
        }
        //权重高的优先
        Instance instance = instances.get(0);
        for (Instance item : instances) {
            if(item.getWeight() > instance.getWeight()) {
                instance = item;
            }
        }
        return instance;
    }
}
